﻿using InspectionMAC.Forms;
using InspectionMAC.SystemThread;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;

public static class MaterialTracker
{
    public enum MaterialStatus
    {
        Created,
        Station1Processed,
        Station2Processed,
        Station3Triggered,
        WaitingForKickDecision, // 新增：等待踢料判断
        Completed,
        Kicked
    }

    public class MaterialInfo
    {
        public string Id { get; }
        public MaterialStatus Status { get; set; }
        public DateTime LastUpdate { get; set; }
        public DateTime CreationTime { get; set; }
        public bool NeedKick { get; set; }
        public bool IsKicked { get; set; }
        public bool IsCompleted { get; set; }
        public uint Sensor2TriggerPosition { get; set; }
        public DateTime CompletionTime { get; set; } // 新增：完成检测时间
        public uint Sensor1TriggerPosition { get; set; }        // 传感器1触发时的轴0位置
        public uint PredictedSensor2Position { get; set; }      // 预测的传感器2触发位置
        public uint ActualSensor2Position { get; set; }         // 实际传感器2触发位置
        public int PositionError { get; set; }                  // 位置误差
        public bool IsMaterialDropped { get; set; }             // 是否掉料
        public DateTime Sensor1TriggerTime { get; set; }        // 传感器1触发时间
        public DateTime Sensor2TriggerTime { get; set; }         // 传感器2触发时间
        public MaterialInfo(string id)
        {
            Id = id;
            Status = MaterialStatus.Created;
            LastUpdate = DateTime.Now;
            CreationTime = DateTime.Now;
            NeedKick = false;
            IsKicked = false;
            IsCompleted = false;
            CompletionTime = DateTime.MinValue;


        }
    }

    private static readonly List<MaterialInfo> _materialList = new List<MaterialInfo>();
    private static readonly object _listLock = new object();
    private static readonly ConcurrentDictionary<string, MaterialInfo> _allMaterials = new ConcurrentDictionary<string, MaterialInfo>();


    public static uint SENSOR1_TO_SENSOR2_DISTANCE { get; set; } = 144726;  // 传感器1到2的预估距离
    public static int ALLOWED_POSITION_ERROR { get; set; } = 3000;         // 允许的位置误差
    public static int MAX_TIME_DELAY_MS { get; set; } = 5000;              // 最大时间延迟

    // 记录传感器1到传感器2的物料追踪
    private static readonly ConcurrentDictionary<string, MaterialTransition> _materialTransitions =
        new ConcurrentDictionary<string, MaterialTransition>();

    private class MaterialTransition
    {
        public string MaterialId { get; set; }
        public uint Sensor1Position { get; set; }
        public uint PredictedSensor2Position { get; set; }
        public DateTime Sensor1Time { get; set; }
        public bool Sensor2Triggered { get; set; }
    }

    // 记录传感器1触发
    public static void RecordSensor1Trigger(string materialId, uint sensor1Position)
    {
        var transition = new MaterialTransition
        {
            MaterialId = materialId,
            Sensor1Position = sensor1Position,
            PredictedSensor2Position = sensor1Position + SENSOR1_TO_SENSOR2_DISTANCE,
            Sensor1Time = DateTime.Now,
            Sensor2Triggered = false
        };

        _materialTransitions.AddOrUpdate(materialId, transition, (id, existing) => transition);

        // 更新物料信息
        if (_allMaterials.TryGetValue(materialId, out var material))
        {
            material.Sensor1TriggerPosition = sensor1Position;
            material.PredictedSensor2Position = transition.PredictedSensor2Position;
            material.Sensor1TriggerTime = DateTime.Now;
        }

        Console.WriteLine($"记录传感器1触发: 物料{materialId}, 位置{sensor1Position}, 预测传感器2位置{transition.PredictedSensor2Position}");
    }

    // 记录传感器2触发并进行掉料检测
    public static bool CheckMaterialDrop(string materialId, uint actualSensor2Position)
    {
        if (!_materialTransitions.TryGetValue(materialId, out var transition))
        {
            Console.WriteLine($"警告: 未找到物料{materialId}的传感器1触发记录");
            return false; // 无法判断，默认未掉料
        }

        // 更新物料信息
        if (_allMaterials.TryGetValue(materialId, out var material))
        {
            material.ActualSensor2Position = actualSensor2Position;
            material.Sensor2TriggerTime = DateTime.Now;
            material.PositionError = Math.Abs((int)actualSensor2Position - (int)transition.PredictedSensor2Position);

            // 检查时间延迟
            var timeDelay = (DateTime.Now - transition.Sensor1Time).TotalMilliseconds;

            // 掉料判断逻辑
            bool isDropped = material.PositionError > ALLOWED_POSITION_ERROR;

            material.IsMaterialDropped = isDropped;
            transition.Sensor2Triggered = true;

            // 清理记录
            _materialTransitions.TryRemove(materialId, out _);

            if (isDropped)
            {
                Console.WriteLine($"掉料检测警告: 物料{materialId}可能已掉料!");
                Console.WriteLine($"位置误差: {material.PositionError} (允许: {ALLOWED_POSITION_ERROR})");
                Console.WriteLine($"预测位置: {transition.PredictedSensor2Position}, 实际位置: {actualSensor2Position}");

                // 触发掉料报警
                TriggerMaterialDropAlarm(materialId);
            }
            else
            {
                Console.WriteLine($"掉料检测正常: 物料{materialId}位置误差{material.PositionError}在允许范围内");
            }

            return isDropped;
        }

        return false;
    }

    // 清理超时的传感器1记录（防止内存泄漏）
    public static void CleanupExpiredTransitions()
    {
        var now = DateTime.Now;
        var expiredMaterials = _materialTransitions.Where(kvp =>
            (now - kvp.Value.Sensor1Time).TotalMilliseconds > MAX_TIME_DELAY_MS * 2)
            .Select(kvp => kvp.Key)
            .ToList();

        foreach (var materialId in expiredMaterials)
        {
            if (_materialTransitions.TryRemove(materialId, out var transition))
            {
                Console.WriteLine($"清理超时传感器1记录: 物料{materialId}, 传感器2未在预期时间内触发");

                // 标记为掉料
                if (_allMaterials.TryGetValue(materialId, out var material))
                {
                    material.IsMaterialDropped = true;
                    TriggerMaterialDropAlarm(materialId);
                }
            }
        }
    }

    private static void TriggerMaterialDropAlarm(string materialId)
    {
        // 触发掉料报警（可以通过DIO输出、声音报警、界面提示等）
        Console.WriteLine($"触发掉料报警: 物料{materialId}");
        DIO_Thread.Do[8] = 1;
        MacTestForm.macTestForm.Invoke(new Action(() =>
        {
            MacTestForm.macTestForm.ShowAlarmForm("物料掉落!");
            MacTestForm.macTestForm.AddLog("物料掉落！");
            MacTestForm.macTestForm.FeedAxisStopBtn_Click(null, EventArgs.Empty);
            MacTestForm.macTestForm.FixedAxisStopBtn_Click(null, EventArgs.Empty);
        }));

    }
    // 创建新物料
    public static string CreateNewMaterial()
    {
        string id = $"{DateTime.Now:yyyyMMddHHmmssfff}_{Guid.NewGuid().ToString("N").Substring(0, 6)}";
        var material = new MaterialInfo(id);

        lock (_listLock)
        {
            if (_allMaterials.TryAdd(id, material))
            {
                _materialList.Add(material);
                _materialList.Sort((a, b) => a.CreationTime.CompareTo(b.CreationTime));
                Console.WriteLine($"创建物料: {id} [状态: {material.Status}, 创建时间: {material.CreationTime:HH:mm:ss.fff}]");
                LogQueueStatus();
                return id;
            }
        }
        return null;
    }

    // 添加物料到追踪器
    public static bool AddMaterial(string materialId, DateTime creationTime)
    {
        var material = new MaterialInfo(materialId)
        {
            CreationTime = creationTime
        };

        lock (_listLock)
        {
            if (_allMaterials.TryAdd(materialId, material))
            {
                _materialList.Add(material);
                _materialList.Sort((a, b) => a.CreationTime.CompareTo(b.CreationTime));
                Console.WriteLine($"添加物料到追踪器: {materialId}");
                return true;
            }
        }
        return false;
    }

    // 获取下一个待处理物料
    public static MaterialInfo GetNextPendingMaterial(MaterialStatus? requiredStatus = null)
    {
        lock (_listLock)
        {
            foreach (var material in _materialList)
            {
                if (requiredStatus.HasValue)
                {
                    if (material.Status == requiredStatus.Value)
                        return material;
                }
                else if (material.Status != MaterialStatus.Completed && material.Status != MaterialStatus.Kicked && material.Status != MaterialStatus.WaitingForKickDecision)
                {
                    return material;
                }
            }
            return null;
        }
    }

    // 获取物料信息
    public static MaterialInfo GetMaterialInfo(string materialId)
    {
        return _allMaterials.TryGetValue(materialId, out var material) ? material : null;
    }

    // 设置踢料信息
    public static void SetKickInfo(string materialId, bool needKick, bool isKicked)
    {
        if (_allMaterials.TryGetValue(materialId, out var material))
        {
            material.NeedKick = needKick;
            material.IsKicked = isKicked;
            material.LastUpdate = DateTime.Now;

            if (isKicked)
            {
                material.Status = MaterialStatus.Kicked;
                Console.WriteLine($"标记物料已踢料: {materialId}");
            }
            else if (needKick)
            {
                Console.WriteLine($"标记物料需要踢料: {materialId}");
            }
        }
        else
        {
            Console.WriteLine($"警告: 未找到物料{materialId}，无法更新踢料状态");
        }
    }

    // 记录传感器二位置
    public static void RecordSensor2Position(string materialId, uint position)
    {
        if (_allMaterials.TryGetValue(materialId, out var material))
        {
            material.Sensor2TriggerPosition = position;
            Console.WriteLine($"[Position] 记录位置: 物料:{materialId} 位置:{position}");
        }
        else
        {
            Console.WriteLine($"[Warning] 无法记录位置: 物料{materialId}不存在");
        }
    }

    // 获取物料位置信息
    public static uint GetSensor2Position(string materialId)
    {
        return _allMaterials.TryGetValue(materialId, out var material) ? material.Sensor2TriggerPosition : 0;
    }

    // 更新物料状态
    private static bool IsValidTransition(MaterialStatus current, MaterialStatus next)
    {
        // 允许从任何状态到相同状态的转换（用于刷新）
        if (current == next)
            return true;

        if (next == MaterialStatus.Station1Processed)
            return current == MaterialStatus.Created;

        if (next == MaterialStatus.Station2Processed)
            return current == MaterialStatus.Station1Processed;

        if (next == MaterialStatus.Station3Triggered)
            return current == MaterialStatus.Station2Processed;

        if (next == MaterialStatus.WaitingForKickDecision)
            return current == MaterialStatus.Station3Triggered;

        if (next == MaterialStatus.Completed)
            return current == MaterialStatus.WaitingForKickDecision;

        if (next == MaterialStatus.Kicked)
            return current == MaterialStatus.WaitingForKickDecision;

        return false;
    }

    // 更新状态转换方法
    public static void UpdateMaterialStatus(string materialId, MaterialStatus newStatus)
    {
        if (_allMaterials.TryGetValue(materialId, out var material))
        {
            // 允许相同状态转换（用于刷新）
            if (material.Status == newStatus)
            {
                material.LastUpdate = DateTime.Now;
                return;
            }

            if (!IsValidTransition(material.Status, newStatus))
            {
                Console.WriteLine($"非法状态转换: {material.Status} → {newStatus}");
                return;
            }

            MaterialStatus oldStatus = material.Status;
            material.Status = newStatus;
            material.LastUpdate = DateTime.Now;

            // 如果是等待踢料判断状态，记录完成时间
            if (newStatus == MaterialStatus.WaitingForKickDecision)
            {
                material.CompletionTime = DateTime.Now;
            }

            Console.WriteLine($"更新物料状态: {materialId} {oldStatus} → {newStatus}");

            // 完成或踢料时移除
            if (newStatus == MaterialStatus.Completed || newStatus == MaterialStatus.Kicked)
            {
                lock (_listLock)
                {
                    _materialList.Remove(material);
                }
                _allMaterials.TryRemove(materialId, out _);
                Console.WriteLine($"物料{newStatus}，从追踪器中移除: {materialId}");
            }
        }
    }

    // 获取队列深度
    public static int GetQueueDepth()
    {
        lock (_listLock)
        {
            int count = 0;
            foreach (var m in _materialList)
            {
                if (m.Status != MaterialStatus.Completed && m.Status != MaterialStatus.Kicked)
                    count++;
            }
            return count;
        }
    }

    // 获取队列快照
    public static List<MaterialInfo> GetQueueSnapshot()
    {
        lock (_listLock)
        {
            return new List<MaterialInfo>(_materialList.Where(m =>
                m.Status != MaterialStatus.Completed && m.Status != MaterialStatus.Kicked));
        }
    }

    // 获取所有活跃物料
    public static List<MaterialInfo> GetAllActiveMaterials()
    {
        return new List<MaterialInfo>(_allMaterials.Values);
    }

    // 获取等待踢料判断的物料（按完成时间排序）
    public static MaterialInfo GetNextWaitingForKickMaterial()
    {
        lock (_listLock)
        {
            var waitingMaterials = _materialList
                .Where(m => m.Status == MaterialStatus.WaitingForKickDecision)
                .OrderBy(m => m.CompletionTime)
                .FirstOrDefault();

            return waitingMaterials;
        }
    }

    // 状态统计
    public static Dictionary<MaterialStatus, int> GetStatusStatistics()
    {
        var stats = new Dictionary<MaterialStatus, int>();
        foreach (MaterialStatus status in Enum.GetValues(typeof(MaterialStatus)))
        {
            stats[status] = 0;
        }

        lock (_listLock)
        {
            foreach (var material in _materialList)
            {
                stats[material.Status]++;
            }
        }
        return stats;
    }

    private static void LogQueueStatus()
    {
        Console.WriteLine($"当前有效队列深度: {GetQueueDepth()}/10");
    }
}